package com.coolingme.springframework.aop.intercept;


import com.coolingme.springframework.aop.aspect.MeJoinPoint;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 见{@link org.aopalliance.intercept.MethodInvocation}
 * 参照{@link org.springframework.aop.framework.ReflectiveMethodInvocation}
 *
 * @author wangyue
 * @date 2024/9/10 22:08
 */
public class MeMethodInvocation implements MeJoinPoint {

    /**
     * 代理对象实例
     */
    protected final Object proxy;

    /**
     * 目标对象实例
     */
    protected final Object target;

    /**
     * 代理方法
     */
    protected final Method method;

    /**
     * 参数
     */
    protected Object[] arguments = new Object[0];

    /**
     * 目标对象Class
     */
    private final Class<?> targetClass;

    private Map<String, Object> userAttributes = new HashMap<String, Object>();

    /**
     * 切面通知拦截器链
     */
    protected final List<?> interceptorsAndDynamicMethodMatchers;

    /**
     * 记录当前执行到链的位置
     */
    private int currentInterceptorIndex = -1;

    public MeMethodInvocation(
            Object proxy, Object target, Method method, Object[] arguments,
            Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers) {

        this.proxy = proxy;
        this.target = target;
        this.targetClass = targetClass;
        this.method = method;
        this.arguments = arguments;
        this.interceptorsAndDynamicMethodMatchers = interceptorsAndDynamicMethodMatchers;
    }

    public Object proceed() throws Throwable {
        /*
        currentInterceptorIndex     size()-1        ++currentInterceptorIndex
                    -1              != 2-1              第0个
                     0              != 2-1              第1个
                     1              == 2-1       切面通知过滤器链执行完，执行自己的方法
         */
        // 执行到最后一个，就调用自己的方法
        if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
            return this.method.invoke(target, this.arguments);
        }

        // 从0开始获取切面通知拦截器
        Object interceptorOrInterceptionAdvice =
                this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);

        // 判断是不是一个拦截器
        if (interceptorOrInterceptionAdvice instanceof MeMethodInterceptor) {
            // 如果是，执行拦截器的方法
            MeMethodInterceptor mi = (MeMethodInterceptor) interceptorOrInterceptionAdvice;
            return mi.invoke(this);
        } else {
            // 动态匹配失败，略过当前拦截器，执行下一个拦截器
            return proceed();
        }
    }

    @Override
    public Object getThis() {
        return this.target;
    }

    @Override
    public Object[] getArguments() {
        return this.arguments;
    }

    @Override
    public Method getMethod() {
        return this.method;
    }

    @Override
    public void setUserAttribute(String key, Object value) {
        this.userAttributes.put(key, value);
    }

    @Override
    public Object getUserAttribute(String key) {
        return this.userAttributes.get(key);
    }
}
